#ifndef MACRO_H
#define MACRO_H

    #include "mousedevice.h"
    #include "keyboarddevice.h"
    #include "processdevice.h"
    #include "memorydevice.h"
    #include "filesystemdevice.h"
    #include "networkdevice.h"
    #include "timerdevice.h"
	#include "ipcdevice.h"
    #include "audiodevice.h"

	#include "misc.h"

    /* Version of MicroMacro */
    #define VERSION_NUMBER			103
    #define BETA_NUMBER				0

    #define PRIORITY_HIGH			1
    #define PRIORITY_NORMAL			0
    #define PRIORITY_LOW			-1

    class Macro
    {
		private:
			bool wineMode;
            bool enableSound;

        protected:
            /* Make sure local copies cannot be created */
            Macro();
            Macro(const Macro &);
            Macro& operator=(const Macro &);

            /* Singleton instance */
            static Macro *pinstance;

            /* Member functions */
            int modifyPermission(HANDLE, const char *, bool);

            /* Devices */
            MouseDevice *mouseDevice;
            KeyboardDevice *keyboardDevice;
            ProcessDevice *processDevice;
            MemoryDevice *memoryDevice;
            FilesystemDevice *filesystemDevice;
            NetworkDevice *networkDevice;
            TimerDevice *timerDevice;
			IpcDevice *ipcDevice;
			AudioDevice *audioDevice;

            /* Variables */
            HWND attachedHwnd;
            bool warningsEnabled;

        public:
            static Macro *instance();
            int init(CLI_OPTIONS * = NULL, CONFIG_OPTIONS * = NULL);
            int cleanup();

            /* Mouse */
            void mouseSetDelay(unsigned int);
            void mouseMove(int, int);
            void mouseSet(int, int);
            void mouseLHold();
            void mouseLRelease();
            void mouseLClick(unsigned int modifier = 0);
            void mouseMHold();
            void mouseMRelease();
            void mouseMClick(unsigned int modifier = 0);
            void mouseRHold();
            void mouseRRelease();
            void mouseRClick(unsigned int modifier = 0);
            void mouseWheelMove(int);
            int mouseGetX();
            int mouseGetY();

            /* Keyboard */
            void keyboardSetDelay(unsigned int);
            void keyboardHold(unsigned int, unsigned int = 0);
            void keyboardRelease(unsigned int, unsigned int = 0);
            void keyboardPress(unsigned int, unsigned int = 0);
			void keyboardState(BYTE *);
            bool keyPressed(unsigned int);
            bool keyPressedLocal(unsigned int);
            void keyboardType(const char *);
            void keyboardBufferClear();
            std::string getKeyName(unsigned int key);

            /* Process */
            int attach(HWND hwnd);
			int attachKeyboard(HWND hwnd);
			int attachMouse(HWND hwnd);
            int detach();
            int forcedDetach();
            HWND getAttachedHwnd();
            HANDLE openProcess(int);
            void closeProcess(HANDLE &);
            DWORD findProcess(std::string, int &);
            DWORD findProcessByExe(std::string, int &);
            DWORD findProcessByWindow(HWND, int &);
			HWND getWindowParent(HWND);
            HWND findWindow(std::string, std::string, int &);
            void findWindowList(std::string, std::string, std::vector<HWND> &,
                int &);
            HWND foregroundWindow();
            HWND getHwnd();
            std::string getWindowName(HWND, int &);
			std::string getWindowClassName(HWND, int &);
            void setWindowName(HWND, std::string &, int &);
            int windowValid(HWND);
            RECT windowRect(HWND);
            WinDC openDC(HWND);
            void closeDC(WinDC &);
            int makeColor(unsigned char, unsigned char, unsigned char);
            unsigned char getR(int);
            unsigned char getG(int);
            unsigned char getB(int);
            int getPixel(WinDC *, int, int);
            void setPixel(WinDC *, int, int, int);
            POINT pixelSearch(WinDC *, int, int, int, int, int,
                unsigned char, int);
            void drawLine(HDC, int, int, int, int, int, int);
            void drawRect(HDC, int, int, int, int, int, int);
            void saveScreenshot(HWND, const char *);
			std::string getClipboard();
			void setClipboard(std::string );
            void showWindow(HWND, int);
            unsigned long findPatternInProcess(HANDLE, unsigned char *, char *,
                unsigned long address, unsigned long);
			unsigned long getModuleAddress(DWORD, const char *);
			void flashWindow(HWND, int);

            /* Filesystem */
            std::string getPath();
            std::string getExecutionPath();
            void setExecutionPath(std::string);
            std::string getFileName(std::string);
            std::string getFilePath(std::string);
            void getDirectory(std::string &, std::vector<std::string> &,
                std::string);
			int isDirectory(const std::string &);

            /* Memory */
            char memoryReadByte(HANDLE, unsigned long, int &);
            unsigned char memoryReadUByte(HANDLE, unsigned long, int &);
            short memoryReadShort(HANDLE, unsigned long, int &);
            unsigned short memoryReadUShort(HANDLE, unsigned long, int &);
            long memoryReadInt(HANDLE, unsigned long, int &);
            unsigned long memoryReadUInt(HANDLE, unsigned long, int &);
            float memoryReadFloat(HANDLE, unsigned long, int &);
			double memoryReadDouble(HANDLE, unsigned long, int &);
            std::string memoryReadString(HANDLE, unsigned long, int &, unsigned int = 0);
            std::wstring memoryReadUString(HANDLE, unsigned long, int &, unsigned int = 0);
            char memoryReadBytePtr(HANDLE, unsigned long, long, int &);
			unsigned char memoryReadUBytePtr(HANDLE, unsigned long, long, int &);
            short memoryReadShortPtr(HANDLE, unsigned long, long, int &);
            unsigned short memoryReadUShortPtr(HANDLE, unsigned long, long, int &);
            long memoryReadIntPtr(HANDLE, unsigned long, long, int &);
            unsigned long memoryReadUIntPtr(HANDLE, unsigned long, long, int &);
            float memoryReadFloatPtr(HANDLE, unsigned long, long, int &);
			double memoryReadDoublePtr(HANDLE, unsigned long, long, int &);
            std::string memoryReadStringPtr(HANDLE, unsigned long, long, int &,
                unsigned int = 0);
            std::wstring memoryReadUStringPtr(HANDLE, unsigned long, long, int &,
                unsigned int = 0);
            void memoryWriteByte(HANDLE, unsigned long, unsigned char, int &);
            void memoryWriteShort(HANDLE, unsigned long, unsigned short, int &);
            //void memoryWriteUShort(HANDLE, long, unsigned short, int &);
            void memoryWriteInt(HANDLE, unsigned long, unsigned long, int &);
            //void memoryWriteUInt(HANDLE, long, unsigned long, int &);
            void memoryWriteFloat(HANDLE, unsigned long, float, int &);
			void memoryWriteDouble(HANDLE, unsigned long, double, int &);
			void memoryWriteString(HANDLE, unsigned long, char *, int &, unsigned int = 0);
			void memoryWriteStringPtr(HANDLE, unsigned long, long, char *, int &, unsigned int = 0);
            void memoryWriteBytePtr(HANDLE, unsigned long, long, unsigned char, int &);
            void memoryWriteShortPtr(HANDLE, unsigned long, long, unsigned short, int &);
            void memoryWriteIntPtr(HANDLE, unsigned long, long, unsigned long, int &);
            //void memoryWriteUIntPtr(HANDLE, long, long, unsigned long, int &);
            void memoryWriteFloatPtr(HANDLE, unsigned long, long, float, int &);
			void memoryWriteDoublePtr(HANDLE, unsigned long, long, double, int &);

			void memoryReadBatch(HANDLE, unsigned long, char *, std::vector<CVardata> &, int &);

            void memoryReadFailReal(HANDLE *, unsigned long, const char *);
            void memoryWriteFailReal(HANDLE *, unsigned long, const char *);

            /* Network */
            void netInit();
            void netPushKey(std::string &, std::string &);
            void netRegisterKeys();
            void netFlushKeys();
            NetCon netOpenCon(const char *, std::string &);
            int netListen(const NetCon &);
            NetCon netPollListen(const NetCon &);
            int netConnect(const NetCon &, const char *);
            int netConnectStatus(const NetCon &);
            int netPollMessages(const NetCon &);
            std::string netGetMessage(const NetCon &);
            int netSendMessage(const NetCon &, const char *, int);
			char *netGetAddress(const NetCon &);
            void netCloseCon(NetCon &);

            /* Timer */
            void newTimer(std::string);
            int removeTimer(std::string);
            int startTimer(std::string, double);
            int isTriggered(std::string);
            LARGE_INTEGER getTime();
			LARGE_INTEGER getTimerFrequency();
            double deltaTime(LARGE_INTEGER, LARGE_INTEGER);

			/* IPC */
			int ipcOpen(DWORD);
			int ipcClose();
			int ipcSend(Message *, Message *);

			void soundPlay(AudioResource *);
			void soundStop(AudioResource *);
			void soundPause(AudioResource *);
			AudioResource *soundLoad(const char *);
			void soundSetLooping(AudioResource *, int);
			void soundSetVolume(AudioResource *, float);
			int soundGetState(AudioResource *);

            /* Misc */
            void clearScreen();
            void rest(unsigned int);
            void setPriority(int);
            void logMessage(std::string);
            void logRaw(std::string);
            int getVersion();
            void setTextColor(int, int);
            void showWarnings(int);

            /* Bitwise operator replacements */
            int bitAnd(int, int);
            int bitOr(int, int);
            int bitLShift(int, int);
            int bitRShift(int, int);

			/* Interfacing */
			void setWineMode(bool);
    };

#endif
